<?php
/**********************
**intellistrip.inc
**Date Created: 4/13/2009
**Copyright 2009 Tomorrow Tech Industries
**Contact: RPITomorrowTech@gmail.com
**********************/

require_once("shared/errors.inc");
require_once("shared/intellistrip.inc");
require_once("dba.inc");
require_once("device.inc");
require_once("intellistrip_client.inc");

class Intellistrip
{	
	//For debugging
	private static $lastError;

	/*******
	Member variables
	*******/
	private $id;

	/********
	Initialization
	********/
	
	//Constructor
	public function __construct($stripID)
	{
		$this->id = $stripID;
	}
	
	//Create an empty intellistrip
	static function createNewIntellistrip(&$intellistripID, $fields)
	{
		//FIXME: how do we get back the intellistrip Id?
		//There should only be a single intellistrip
		$hostName = 'localhost';
		if( isset($fields['hostName']) )
		{
			$hostName = $fields['hostName'];
		}
		$serverPath = 'software_intellistrip/xml_rpc_server_hardware.php';
		if( isset($fields['serverPath']) )
		{
			$serverPath = $fields['serverPath'];
		}
		$port = '80';
		if( isset($fields['port']) )
		{
			$port = $fields['port'];
		}
		$password = 'intellimation';
		if( isset($fields['password']) )
		{
			$password = $fields['password'];
		}
		$roomID = '1';
		if( isset($fields['roomID']) )
		{
			$roomID = $fields['roomID'];
		}
		$state = '0';
		if( isset($fields['state']) )
		{
			$state = $fields['state'];
		}
		$serialNum = 'SER-1234567';
		if( isset($fields['serialNum']) )
		{
			$serialNum = $fields['serialNum'];
		}
		// $macAddress = '0';
		// if( isset($fields['macAddress']) )
		// {
		// 	$macAddress = $fields['macAddress'];
		// }
		$name = 'Unnamed Intellistrip';
		if( isset($fields['name']) )
		{
			$name = $fields['name'];
		}
		
		//Escape the values
		$hostName = DBaccess::GetSQLValueString($hostName, 'text');
		$serverPath = DBaccess::GetSQLValueString($serverPath, 'text');
		$port = DBaccess::GetSQLValueString($port, 'int');
		$password = DBaccess::GetSQLValueString($password, 'text');
		$roomID = DBaccess::GetSQLValueString($roomID, 'int');
		$state = DBaccess::GetSQLValueString($state, 'int');
		$serialNum = DBaccess::GetSQLValueString($serialNum, 'text');
		//$macAddress = DBaccess::GetSQLValueString($macAddress, 'text');
		$name = DBaccess::GetSQLValueString($name, 'text');

		//id is auto-incremented to form its value
		$q = "INSERT INTO Intellistrip 
				(hostName, serverPath, port, password, roomID, state, serialNum, name) 
				VALUES ($hostName, $serverPath, $port, $password, $roomID, $state, $serialNum, $name)";
		$db = new DBaccess(); 
		$rc = $db->executeQuery($q, $result);
		if( TT_FAILED($rc) )
		{
			Intellistrip::setLastError("Couldn't execute query: " . $q);
			return $rc;
		}
		
		//Seems auto increment will not repeat deleted values (ie even if holes are present)
		$q = "SELECT MAX(stripID) FROM Intellistrip WHERE name=$name";
		$rc = $db->executeQuery($q, $result);
		if( TT_FAILED($rc) )
		{
			Intellistrip::setLastError("Couldn't execute query: " . $q);
			return $rc;
		}
		$row = mysql_fetch_array($result);
		$intellistripID = $row[0];
		
		return TT_OK;
	}
	
	/*********
	Utility
	*********/
	
	private function getIntellistripClient(&$client)
	{
		//TODO: Some bug causing specified connections to not work, fix later
		//Query all of the connection parameters
		
		$rc = $this->getHostName($serverAddress);
		if( TT_FAILED($rc) )
		{
			return $rc;
		}
		
		$rc = $this->getServerPath($serverPath);
		if( TT_FAILED($rc) )
		{
			return $rc;
		}

		$rc = $this->getPort($serverPort);
		if( TT_FAILED($rc) )
		{
			return $rc;
		}

		$rc = $this->getPassword($serverPassword);
		if( TT_FAILED($rc) )
		{
			return $rc;
		}

		//Setup the client object with our connection parameters
		$client = new IntellistripClient(array('serverAddress' => $serverAddress,
											'serverPath' => $serverPath, 
											'serverPort' => $serverPort, 
											'serverPassword' => $serverPassword));
		//$client = new IntellistripClient(array());
		return TT_OK;
	}
	
	//Returns an array of Intellistrips
	public static function getIntellistrips(&$intellistrips)
	{
		$q = "SELECT stripID from Intellistrip ORDER BY stripID";
		$db = new DBaccess(); 
		$rc = $db->executeQuery($q, $result);
		if( TT_FAILED($rc) )
		{
			Intellistrip::setLastError("Couldn't execute query: " . $q);
			return $rc;
		}
		$intellistrips = array();

		//Add in all of the intellistrip IDs
		while( $row = mysql_fetch_array($result) )
		{
			array_push($intellistrips, new Intellistrip($row[0]));
		}

		return TT_OK;
	}
		
	//All get requests are essentially the same
	//Get a single column value matching the current intellistrip id
	private function getColumn($column, &$value)
	{
		//There should only be a single intellistrip
		$q = "SELECT $column FROM Intellistrip WHERE stripID='{$this->id}' LIMIT 1";
		$db = new DBaccess(); 
		$rc = $db->executeQuery($q, $result);
		if( TT_FAILED($rc) )
		{
			Intellistrip::setLastError("Couldn't execute query: " . $q);
			return $rc;
		}
		$row = mysql_fetch_array($result);
		$value = $row[0];
		return TT_OK;
	}
		
	public static function getLastError()
	{
		return Intellistrip::$lastError;
	}
	
	public static function clearLastError()
	{
		Intellistrip::$lastError = '';
	}
	
	protected static function setLastError($error)
	{
		Intellistrip::$lastError = $error;
	}
	
	//All set requests are essentially the same
	//Update a single column matching the current intellistrip id to a certain value
	//Value must already be escaped prior to entering this function
	private function setColumn($column, $value)
	{
		//There should only be a single intellistrip
		//Example: the following are equivilent:
		$q = "UPDATE Intellistrip SET $column=$value WHERE stripID={$this->id} LIMIT 1";
		$db = new DBaccess(); 
		$rc = $db->executeQuery($q, $result);
		if( TT_FAILED($rc) )
		{
			Intellistrip::setLastError($db->getLastError());
			return $rc;
		}

		return TT_OK;
	}

	/*****
	Accessor/mutator
	*****/
	
	public function getIntellistripID(&$intellistripID)
	{
		$intellistripID = $this->id;
		return TT_OK;
	}
	
	//Intellistrip id is relativly immutable, in this object
	//It should only be changed if the database itself is changed
	public function setIntellistripID($intellistripID)
	{
		$intellistripID = DBaccess::GetSQLValueString($intellistripID, 'int');
		$rc = $this->setColumn("stripID", $intellistripID);
		//Only update this id if it really was updated
		if( TT_SUCCEEDED($rc) )
		{
			$this->id = $intellistripID;
		}
		return $rc;
	}

	public function getHostName(&$hostName)
	{
		return $this->getColumn("hostName", $hostName);
	}

	public function setHostName($hostName)
	{
		return $this->setColumn("hostName", DBaccess::GetSQLValueString($hostName, 'text'));
	}

	public function getServerPath(&$serverPath)
	{
		return $this->getColumn("serverPath", $serverPath);
	}

	public function setServerPath($serverPath)
	{
		return $this->setColumn("serverPath", DBaccess::GetSQLValueString($serverPath, 'text'));
	}

	public function getPort(&$port)
	{
		return $this->getColumn("port", $port);
	}

	public function setPort($port)
	{
		return $this->setColumn("port", DBaccess::GetSQLValueString($port, 'int'));
	}
	public function getPassword(&$password)
	{
		return $this->getColumn("password", $password);
	}

	public function setPassword($password)
	{
		return $this->setColumn("password", DBaccess::GetSQLValueString($password, 'text'));
	}
	public function getRoomID(&$roomID)
	{
		return $this->getColumn("roomID", $roomID);
	}

	public function setRoomID($roomID)
	{
		return $this->setColumn("roomID", DBaccess::GetSQLValueString($roomID, 'int'));
	}
	public function getState(&$state)
	{
		return $this->getColumn("state", $state);
	}

	public function setState($state)
	{
		return $this->setColumn("state", DBaccess::GetSQLValueString($state, 'int'));
	}
	public function getSerialNum(&$serialNum)
	{
		return $this->getColumn("serialNum", $serialNum);
	}

	public function setSerialNum($serialNum)
	{
		return $this->setColumn("serialNum", DBaccess::GetSQLValueString($serialNum, 'text'));
	}
	// public function getMacAddress(&$macAddress)
	// {
	// 	return $this->getColumn("macAddress", $macAddress);
	// }
	// 
	// public function setMacAddress($macAddress)
	// {
	// 	return $this->setColumn("macAddress", DBaccess::GetSQLValueString($macAddress, 'text'));
	// }
	public function getName(&$name)
	{
		return $this->getColumn("name", $name);
	}

	public function setName($name)
	{
		return $this->setColumn("name", DBaccess::GetSQLValueString($name, 'text'));
	}
	
	/********
	Misc functions
	********/
	
	public function getPortPower($portNum, &$powerLevel)
	{
		$rc = $this->getIntellistripClient($client);
		if( TT_FAILED($rc) )
		{
			return $rc;
		}
		$rc = $client->getPortPower($portNum, $powerLevel);
		if( TT_FAILED($rc) )
		{
			Intellistrip::SetLastError("Failed to get port power: " . $client->getLastError());
		}
		return $rc;
	}
	
	public function setPortPower($portNum, $powerLevel)
	{
		$rc = $this->getIntellistripClient($client);
		if( TT_FAILED($rc) )
		{
			return $rc;
		}
		$rc = $client->setPortPower($portNum, $powerLevel);
		if( TT_FAILED($rc) )
		{
			Intellistrip::SetLastError("Failed to set port power: " . $client->getLastError());
		}
		return $rc;
	}

	public function getString()
	{
		$ret = "id: " . $this->id;
		return $ret;
	}
	
	//Return a mapped list of $portId => $deviceObject list of devices
	public function getDevices(&$devices)
	{
		return Device::getDevicesByStripId($this->id, $devices);
	}
	
	//Associate a device to a specific port, clearing any previous devices on that port
	//If an old device was present, it is orphaned and still stays in the device list
	public function setDevice($device, $portNum)
	{
		if( !isset($device) || !isset($portNum) )
		{
			return TT_GENERAL;
		}
		//Fetch the device id
		$rc = $device->getDeviceId($devId);
		if( TT_FAILED($rc) )
		{
			Intellistrip::setLastError("Couldn't get device id");
			return $rc;
		}

		//Clear out any old entries
		$q = "DELETE FROM Port WHERE "
			//Clear out old entries on this port
			. "(stripID=" . $this->id . " AND portNum=" . $portNum . ")"
			//Clear out old entries for this device
			. "OR (devID=" . $devId . ")
			";
		$db = new DBaccess(); 
		$rc = $db->executeQuery($q, $result);
		if( TT_FAILED($rc) )
		{
			Intellistrip::setLastError("Couldn't execute query: " . $q);
			return $rc;
		}
		
		//Register the add
		$q = "INSERT INTO Port(stripID, devID, portNum) VALUES(" . $this->id . ", " . $devId . ", " . $portNum. ")";
		$rc = $db->executeQuery($q, $result);
		if( TT_FAILED($rc) )
		{
			Intellistrip::setLastError("Couldn't execute query: " . $q);
			return $rc;
		}
		
		//We deleted old values and inserted the new one, we are done
		return TT_OK;
	}

	//Get the first device found on this port
	//Later on we may wish to return this as an array
	public function getDevice(&$device, $portNum)
	{
		//Must be a valid port id
		if( $portNum < INTELLISTRIP_PORT_BASE || $portNum >= INTELLISTRIP_PORT_BASE + INTELLISTRIP_NUMBER_PORTS )
		{
			return TT_INVALID_INPUT;
		}
	
		$rc = $this->getDevices($devicesPortMapped);
		if( TT_FAILED($rc) )
		{
			return $rc;
		}

		//Start with empty list
		$devicesIndexed = array();
		
		//For now we only support direct mapping of devices to ports
		for( $i = 0; $i < INTELLISTRIP_NUMBER_PORTS; $i = $i + 1 )
		{
			//Default to no device
			$device = null;
			//TRy to match up a device
			foreach( $devicesPortMapped as $key => $value )
			{
				if( $value['port'] == $i + INTELLISTRIP_PORT_BASE )
				{
					$device = $value['device'];
					break;
				}
			}
			
			array_push($devicesIndexed, $device);
		}
		
		$device = $devicesIndexed[$portNum - INTELLISTRIP_PORT_BASE];
		//Make sure device is valid
		if( $device == null )
		{
			return TT_GENERAL;
		}
		
		return TT_OK;
	}

	//Test it
	public static function testIntellistrip()
	{
		//Intellistrip::createNewIntellistrip($stripID, array('type' => '1', 'name' => 'VCR'));
		if( TT_FAILED(Intellistrip::getIntellistrips($intellistrips)) )
		{
			echo "Failed to get intellistrips!<BR>";
		}
		else
		{
			if( count($intellistrips) == 0 )
			{
				echo "No intellistrips!<BR>\n";
			}
			else
			{
				echo "Intellistrips:<BR>\n";
				foreach( $intellistrips as $key => $value )
				{
					echo "Intellistrip id: $value<BR>";
					$intellistrip = $value;
					
					Intellistrip::testGetter($intellistrip, "getIntellistripID");
					Intellistrip::testGetter($intellistrip, "getHostName");
					Intellistrip::testGetter($intellistrip, "getServerPath");
					Intellistrip::testGetter($intellistrip, "getPort");
					Intellistrip::testGetter($intellistrip, "getPassword");
					Intellistrip::testGetter($intellistrip, "getRoomID");
					Intellistrip::testGetter($intellistrip, "getState");
					Intellistrip::testGetter($intellistrip, "getSerialNum");
					//Intellistrip::testGetter($intellistrip, "getMacAddress");
					Intellistrip::testGetter($intellistrip, "getName");
				}
			}
		}
	
		return true;
	}

	//Print member function tests
	public static function testGetter($intellistrip, $function)
	{
		$rc = $intellistrip->$function($ret);
		//Begine the print
		echo "&nbsp;&nbsp;&nbsp;$function: ";
		if( TT_SUCCEEDED($rc) )
		{
			echo "$ret";
		}
		else
		{
			echo "ERROR: " . errorString($rc);
		}
		//End the line
		echo "<BR>\n";
		return $rc;
	}
}


?>
